{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "f110e018",
      "metadata": {},
      "source": [
        "# Visualising predictions\n",
        "\n",
        "<a target=\"_blank\" href=\"https://colab.research.google.com/github/moj-analytical-services/splink/blob/master/docs/demos/tutorials/06_Visualising_predictions.ipynb\">\n",
        "  <img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/>\n",
        "</a>\n",
        "\n",
        "Splink contains a variety of tools to help you visualise your predictions.\n",
        "\n",
        "The idea is that, by developing an understanding of how your model works, you can gain confidence that the predictions it makes are sensible, or alternatively find examples of where your model isn't working, which may help you improve the model specification and fix these problems.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "1e3eed24",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2024-06-22T08:35:35.067665Z",
          "iopub.status.busy": "2024-06-22T08:35:35.067291Z",
          "iopub.status.idle": "2024-06-22T08:35:35.087061Z",
          "shell.execute_reply": "2024-06-22T08:35:35.085914Z"
        },
        "tags": [
          "hide_input"
        ]
      },
      "outputs": [],
      "source": [
        "# Uncomment and run this cell if you're running in Google Colab.\n",
        "# !pip install splink"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "fb29d421",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2024-06-22T08:35:35.091703Z",
          "iopub.status.busy": "2024-06-22T08:35:35.091361Z",
          "iopub.status.idle": "2024-06-22T08:35:37.305178Z",
          "shell.execute_reply": "2024-06-22T08:35:37.304151Z"
        },
        "tags": []
      },
      "outputs": [],
      "source": [
        "# Rerun our predictions to we're ready to view the charts\n",
        "from splink import Linker, DuckDBAPI, splink_datasets\n",
        "\n",
        "import pandas as pd\n",
        "\n",
        "pd.options.display.max_columns = 1000\n",
        "\n",
        "db_api = DuckDBAPI()\n",
        "df = splink_datasets.fake_1000"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "2733ac16",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2024-06-22T08:35:37.309398Z",
          "iopub.status.busy": "2024-06-22T08:35:37.309063Z",
          "iopub.status.idle": "2024-06-22T08:35:37.869364Z",
          "shell.execute_reply": "2024-06-22T08:35:37.868626Z"
        }
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "\n",
            " -- WARNING --\n",
            "You have called predict(), but there are some parameter estimates which have neither been estimated or specified in your settings dictionary.  To produce predictions the following untrained trained parameters will use default values.\n",
            "Comparison: 'email':\n",
            "    m values not fully trained\n"
          ]
        }
      ],
      "source": [
        "import json\n",
        "import urllib\n",
        "\n",
        "url = \"https://raw.githubusercontent.com/moj-analytical-services/splink/847e32508b1a9cdd7bcd2ca6c0a74e547fb69865/docs/demos/demo_settings/saved_model_from_demo.json\"\n",
        "\n",
        "with urllib.request.urlopen(url) as u:\n",
        "    settings = json.loads(u.read().decode())\n",
        "\n",
        "\n",
        "linker = Linker(df, settings, db_api=DuckDBAPI())\n",
        "df_predictions = linker.inference.predict(threshold_match_probability=0.2)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7b0dedd9",
      "metadata": {},
      "source": [
        "## Waterfall chart\n",
        "\n",
        "The waterfall chart provides a means of visualising individual predictions to understand how Splink computed the final matchweight for a particular pairwise record comparison.\n",
        "\n",
        "To plot a waterfall chart, the user chooses one or more records from the results of `linker.inference.predict()`, and provides these records to the [`linker.visualisations.waterfall_chart()`](../../api_docs/visualisations.md#splink.internals.linker_components.visualisations.LinkerVisualisations.waterfall_chart) function.\n",
        "\n",
        "For an introduction to waterfall charts and how to interpret them, please see [this](https://www.youtube.com/watch?v=msz3T741KQI&t=507s) video.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "bbfdc70c",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2024-06-22T08:35:37.873246Z",
          "iopub.status.busy": "2024-06-22T08:35:37.872959Z",
          "iopub.status.idle": "2024-06-22T08:35:38.614805Z",
          "shell.execute_reply": "2024-06-22T08:35:38.614251Z"
        },
        "tags": []
      },
      "outputs": [
        {
          "data": {
            "text/html": [
              "\n",
              "<style>\n",
              "  #altair-viz-797c285cdb8b47c884b5745f2cee157d.vega-embed {\n",
              "    width: 100%;\n",
              "    display: flex;\n",
              "  }\n",
              "\n",
              "  #altair-viz-797c285cdb8b47c884b5745f2cee157d.vega-embed details,\n",
              "  #altair-viz-797c285cdb8b47c884b5745f2cee157d.vega-embed details summary {\n",
              "    position: relative;\n",
              "  }\n",
              "</style>\n",
              "<div id=\"altair-viz-797c285cdb8b47c884b5745f2cee157d\"></div>\n",
              "<script type=\"text/javascript\">\n",
              "  var VEGA_DEBUG = (typeof VEGA_DEBUG == \"undefined\") ? {} : VEGA_DEBUG;\n",
              "  (function(spec, embedOpt){\n",
              "    let outputDiv = document.currentScript.previousElementSibling;\n",
              "    if (outputDiv.id !== \"altair-viz-797c285cdb8b47c884b5745f2cee157d\") {\n",
              "      outputDiv = document.getElementById(\"altair-viz-797c285cdb8b47c884b5745f2cee157d\");\n",
              "    }\n",
              "    const paths = {\n",
              "      \"vega\": \"https://cdn.jsdelivr.net/npm/vega@5?noext\",\n",
              "      \"vega-lib\": \"https://cdn.jsdelivr.net/npm/vega-lib?noext\",\n",
              "      \"vega-lite\": \"https://cdn.jsdelivr.net/npm/vega-lite@5.17.0?noext\",\n",
              "      \"vega-embed\": \"https://cdn.jsdelivr.net/npm/vega-embed@6?noext\",\n",
              "    };\n",
              "\n",
              "    function maybeLoadScript(lib, version) {\n",
              "      var key = `${lib.replace(\"-\", \"\")}_version`;\n",
              "      return (VEGA_DEBUG[key] == version) ?\n",
              "        Promise.resolve(paths[lib]) :\n",
              "        new Promise(function(resolve, reject) {\n",
              "          var s = document.createElement('script');\n",
              "          document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
              "          s.async = true;\n",
              "          s.onload = () => {\n",
              "            VEGA_DEBUG[key] = version;\n",
              "            return resolve(paths[lib]);\n",
              "          };\n",
              "          s.onerror = () => reject(`Error loading script: ${paths[lib]}`);\n",
              "          s.src = paths[lib];\n",
              "        });\n",
              "    }\n",
              "\n",
              "    function showError(err) {\n",
              "      outputDiv.innerHTML = `<div class=\"error\" style=\"color:red;\">${err}</div>`;\n",
              "      throw err;\n",
              "    }\n",
              "\n",
              "    function displayChart(vegaEmbed) {\n",
              "      vegaEmbed(outputDiv, spec, embedOpt)\n",
              "        .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));\n",
              "    }\n",
              "\n",
              "    if(typeof define === \"function\" && define.amd) {\n",
              "      requirejs.config({paths});\n",
              "      require([\"vega-embed\"], displayChart, err => showError(`Error loading script: ${err.message}`));\n",
              "    } else {\n",
              "      maybeLoadScript(\"vega\", \"5\")\n",
              "        .then(() => maybeLoadScript(\"vega-lite\", \"5.17.0\"))\n",
              "        .then(() => maybeLoadScript(\"vega-embed\", \"6\"))\n",
              "        .catch(showError)\n",
              "        .then(() => displayChart(vegaEmbed));\n",
              "    }\n",
              "  })({\"config\": {\"view\": {\"continuousWidth\": 400, \"continuousHeight\": 300}}, \"layer\": [{\"layer\": [{\"mark\": \"rule\", \"encoding\": {\"color\": {\"value\": \"black\"}, \"size\": {\"value\": 0.5}, \"y\": {\"field\": \"zero\", \"type\": \"quantitative\"}}}, {\"mark\": {\"type\": \"bar\", \"width\": 60}, \"encoding\": {\"color\": {\"condition\": {\"test\": \"(datum.log2_bayes_factor < 0)\", \"value\": \"red\"}, \"value\": \"green\"}, \"opacity\": {\"condition\": {\"test\": \"datum.column_name == 'Prior match weight' || datum.column_name == 'Final score'\", \"value\": 1}, \"value\": 0.5}, \"tooltip\": [{\"field\": \"column_name\", \"title\": \"Comparison column\", \"type\": \"nominal\"}, {\"field\": \"value_l\", \"title\": \"Value (L)\", \"type\": \"nominal\"}, {\"field\": \"value_r\", \"title\": \"Value (R)\", \"type\": \"nominal\"}, {\"field\": \"label_for_charts\", \"title\": \"Label\", \"type\": \"ordinal\"}, {\"field\": \"sql_condition\", \"title\": \"SQL condition\", \"type\": \"nominal\"}, {\"field\": \"comparison_vector_value\", \"title\": \"Comparison vector value\", \"type\": \"nominal\"}, {\"field\": \"bayes_factor\", \"format\": \",.4f\", \"title\": \"Bayes factor = m/u\", \"type\": \"quantitative\"}, {\"field\": \"log2_bayes_factor\", \"format\": \",.4f\", \"title\": \"Match weight = log2(m/u)\", \"type\": \"quantitative\"}, {\"field\": \"prob\", \"format\": \".4f\", \"title\": \"Cumulative match probability\", \"type\": \"quantitative\"}, {\"field\": \"bayes_factor_description\", \"title\": \"Match weight description\", \"type\": \"nominal\"}], \"x\": {\"axis\": {\"grid\": true, \"labelAlign\": \"center\", \"labelAngle\": -20, \"labelExpr\": \"datum.value == 'Prior' || datum.value == 'Final score' ? '' : datum.value\", \"labelPadding\": 10, \"tickBand\": \"extent\", \"title\": \"Column\"}, \"field\": \"column_name\", \"sort\": {\"field\": \"bar_sort_order\", \"order\": \"ascending\"}, \"type\": \"nominal\"}, \"y\": {\"axis\": {\"grid\": false, \"orient\": \"left\", \"title\": \"Match Weight\"}, \"field\": \"previous_sum\", \"type\": \"quantitative\"}, \"y2\": {\"field\": \"sum\"}}}, {\"mark\": {\"type\": \"text\", \"fontWeight\": \"bold\"}, \"encoding\": {\"color\": {\"value\": \"white\"}, \"text\": {\"condition\": {\"test\": \"abs(datum.log2_bayes_factor) > 1\", \"field\": \"log2_bayes_factor\", \"format\": \".2f\", \"type\": \"nominal\"}, \"value\": \"\"}, \"x\": {\"axis\": {\"labelAngle\": -20, \"title\": \"Column\"}, \"field\": \"column_name\", \"sort\": {\"field\": \"bar_sort_order\", \"order\": \"ascending\"}, \"type\": \"nominal\"}, \"y\": {\"axis\": {\"orient\": \"left\"}, \"field\": \"center\", \"type\": \"quantitative\"}}}, {\"mark\": {\"type\": \"text\", \"baseline\": \"bottom\", \"dy\": -25, \"fontWeight\": \"bold\"}, \"encoding\": {\"color\": {\"value\": \"black\"}, \"text\": {\"field\": \"column_name\", \"type\": \"nominal\"}, \"x\": {\"axis\": {\"labelAngle\": -20, \"title\": \"Column\"}, \"field\": \"column_name\", \"sort\": {\"field\": \"bar_sort_order\", \"order\": \"ascending\"}, \"type\": \"nominal\"}, \"y\": {\"field\": \"sum_top\", \"type\": \"quantitative\"}}}, {\"mark\": {\"type\": \"text\", \"baseline\": \"bottom\", \"dy\": -13, \"fontSize\": 8}, \"encoding\": {\"color\": {\"value\": \"grey\"}, \"text\": {\"field\": \"value_l\", \"type\": \"nominal\"}, \"x\": {\"axis\": {\"labelAngle\": -20, \"title\": \"Column\"}, \"field\": \"column_name\", \"sort\": {\"field\": \"bar_sort_order\", \"order\": \"ascending\"}, \"type\": \"nominal\"}, \"y\": {\"field\": \"sum_top\", \"type\": \"quantitative\"}}}, {\"mark\": {\"type\": \"text\", \"baseline\": \"bottom\", \"dy\": -5, \"fontSize\": 8}, \"encoding\": {\"color\": {\"value\": \"grey\"}, \"text\": {\"field\": \"value_r\", \"type\": \"nominal\"}, \"x\": {\"axis\": {\"labelAngle\": -20, \"title\": \"Column\"}, \"field\": \"column_name\", \"sort\": {\"field\": \"bar_sort_order\", \"order\": \"ascending\"}, \"type\": \"nominal\"}, \"y\": {\"field\": \"sum_top\", \"type\": \"quantitative\"}}}]}, {\"mark\": {\"type\": \"rule\", \"color\": \"black\", \"strokeWidth\": 2, \"x2Offset\": 30, \"xOffset\": -30}, \"encoding\": {\"x\": {\"axis\": {\"labelAngle\": -20, \"title\": \"Column\"}, \"field\": \"column_name\", \"sort\": {\"field\": \"bar_sort_order\", \"order\": \"ascending\"}, \"type\": \"nominal\"}, \"x2\": {\"field\": \"lead\"}, \"y\": {\"axis\": {\"labelExpr\": \"format(1 / (1 + pow(2, -1*datum.value)), '.2r')\", \"orient\": \"right\", \"title\": \"Probability\"}, \"field\": \"sum\", \"scale\": {\"zero\": false}, \"type\": \"quantitative\"}}}], \"data\": {\"name\": \"data-1ca707d1d3376dead13c88025800ec55\"}, \"height\": 450, \"params\": [{\"name\": \"record_number\", \"bind\": {\"input\": \"range\", \"max\": 4, \"min\": 0, \"step\": 1}, \"value\": 0}], \"resolve\": {\"axis\": {\"y\": \"independent\"}}, \"title\": {\"text\": \"Match weights waterfall chart\", \"subtitle\": \"How each comparison contributes to the final match score\"}, \"transform\": [{\"filter\": \"(datum.record_number == record_number)\"}, {\"window\": [{\"op\": \"sum\", \"field\": \"log2_bayes_factor\", \"as\": \"sum\"}, {\"op\": \"lead\", \"field\": \"column_name\", \"as\": \"lead\"}], \"frame\": [null, 0]}, {\"calculate\": \"datum.column_name === \\\"Final score\\\" ? datum.sum - datum.log2_bayes_factor : datum.sum\", \"as\": \"sum\"}, {\"calculate\": \"datum.lead === null ? datum.column_name : datum.lead\", \"as\": \"lead\"}, {\"calculate\": \"datum.column_name === \\\"Final score\\\" || datum.column_name === \\\"Prior match weight\\\" ? 0 : datum.sum - datum.log2_bayes_factor\", \"as\": \"previous_sum\"}, {\"calculate\": \"datum.sum > datum.previous_sum ? datum.column_name : \\\"\\\"\", \"as\": \"top_label\"}, {\"calculate\": \"datum.sum < datum.previous_sum ? datum.column_name : \\\"\\\"\", \"as\": \"bottom_label\"}, {\"calculate\": \"datum.sum > datum.previous_sum ? datum.sum : datum.previous_sum\", \"as\": \"sum_top\"}, {\"calculate\": \"datum.sum < datum.previous_sum ? datum.sum : datum.previous_sum\", \"as\": \"sum_bottom\"}, {\"calculate\": \"(datum.sum + datum.previous_sum) / 2\", \"as\": \"center\"}, {\"calculate\": \"(datum.log2_bayes_factor > 0 ? \\\"+\\\" : \\\"\\\") + datum.log2_bayes_factor\", \"as\": \"text_log2_bayes_factor\"}, {\"calculate\": \"datum.sum < datum.previous_sum ? 4 : -4\", \"as\": \"dy\"}, {\"calculate\": \"datum.sum < datum.previous_sum ? \\\"top\\\" : \\\"bottom\\\"\", \"as\": \"baseline\"}, {\"calculate\": \"1. / (1 + pow(2, -1.*datum.sum))\", \"as\": \"prob\"}, {\"calculate\": \"0*datum.sum\", \"as\": \"zero\"}], \"width\": {\"step\": 75}, \"$schema\": \"https://vega.github.io/schema/vega-lite/v5.9.3.json\", \"datasets\": {\"data-1ca707d1d3376dead13c88025800ec55\": [{\"column_name\": \"Prior\", \"label_for_charts\": \"Starting match weight (prior)\", \"sql_condition\": null, \"log2_bayes_factor\": -8.386106589561935, \"bayes_factor\": 0.002989030659078392, \"comparison_vector_value\": null, \"m_probability\": null, \"u_probability\": null, \"bayes_factor_description\": null, \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": null, \"bar_sort_order\": 0, \"record_number\": 0}, {\"sql_condition\": \"\\\"first_name_l\\\" = \\\"first_name_r\\\"\", \"label_for_charts\": \"Exact match on first_name\", \"m_probability\": 0.49142094931763786, \"u_probability\": 0.0057935713975033705, \"bayes_factor\": 84.82176460782142, \"log2_bayes_factor\": 6.406362591550453, \"comparison_vector_value\": 4, \"bayes_factor_description\": \"If comparison level is `exact match on first_name` then comparison is 84.82 times more likely to be a match\", \"column_name\": \"first_name\", \"value_l\": \"Kai\", \"value_r\": \"Kai\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 1, \"record_number\": 0}, {\"sql_condition\": \"\\\"first_name_l\\\" = \\\"first_name_r\\\"\", \"label_for_charts\": \"Term freq adjustment on first_name with weight {cl.tf_adjustment_weight}\", \"m_probability\": null, \"u_probability\": null, \"bayes_factor\": 0.9628915662650601, \"log2_bayes_factor\": -0.05455475332923131, \"comparison_vector_value\": 4, \"bayes_factor_description\": \"Term frequency adjustment on first_name makes comparison  1.04 times less likely to be a match\", \"column_name\": \"tf_first_name\", \"value_l\": \"Kai\", \"value_r\": \"Kai\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 2, \"record_number\": 0}, {\"sql_condition\": \"\\\"surname_l\\\" IS NULL OR \\\"surname_r\\\" IS NULL\", \"label_for_charts\": \"surname is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `surname is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"surname\", \"value_l\": \"None\", \"value_r\": \"Turner\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 3, \"record_number\": 0}, {\"sql_condition\": \"\\\"surname_l\\\" IS NULL OR \\\"surname_r\\\" IS NULL\", \"label_for_charts\": \"surname is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `surname is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"tf_surname\", \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 4, \"record_number\": 0}, {\"sql_condition\": \"ELSE\", \"label_for_charts\": \"All other comparisons\", \"m_probability\": 0.4592001552927498, \"u_probability\": 0.9966506506506506, \"bayes_factor\": 0.4607433457179473, \"log2_bayes_factor\": -1.1179647649923994, \"comparison_vector_value\": 0, \"bayes_factor_description\": \"If comparison level is `all other comparisons` then comparison is  2.17 times less likely to be a match\", \"column_name\": \"dob\", \"value_l\": \"2018-12-31\", \"value_r\": \"2009-11-03\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 5, \"record_number\": 0}, {\"sql_condition\": \"\\\"city_l\\\" = \\\"city_r\\\"\", \"label_for_charts\": \"Exact match on city\", \"m_probability\": 0.5625747223574914, \"u_probability\": 0.0551475711801453, \"bayes_factor\": 10.201260188228096, \"log2_bayes_factor\": 3.350675477967206, \"comparison_vector_value\": 1, \"bayes_factor_description\": \"If comparison level is `exact match on city` then comparison is 10.20 times more likely to be a match\", \"column_name\": \"city\", \"value_l\": \"London\", \"value_r\": \"London\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 6, \"record_number\": 0}, {\"sql_condition\": \"\\\"city_l\\\" = \\\"city_r\\\"\", \"label_for_charts\": \"Term freq adjustment on city with weight {cl.tf_adjustment_weight}\", \"m_probability\": null, \"u_probability\": null, \"bayes_factor\": 0.2591617073379083, \"log2_bayes_factor\": -1.948075527570922, \"comparison_vector_value\": 1, \"bayes_factor_description\": \"Term frequency adjustment on city makes comparison  3.86 times less likely to be a match\", \"column_name\": \"tf_city\", \"value_l\": \"London\", \"value_r\": \"London\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 7, \"record_number\": 0}, {\"sql_condition\": \"\\\"email_l\\\" IS NULL OR \\\"email_r\\\" IS NULL\", \"label_for_charts\": \"email is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `email is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"email\", \"value_l\": \"k.t50eherand@z.ncom\", \"value_r\": \"None\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 8, \"record_number\": 0}, {\"sql_condition\": \"\\\"email_l\\\" IS NULL OR \\\"email_r\\\" IS NULL\", \"label_for_charts\": \"email is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `email is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"tf_email\", \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 9, \"record_number\": 0}, {\"column_name\": \"Final score\", \"label_for_charts\": \"Final score\", \"sql_condition\": null, \"log2_bayes_factor\": -1.7496635659368296, \"bayes_factor\": 0.29737111711119135, \"comparison_vector_value\": null, \"m_probability\": null, \"u_probability\": null, \"bayes_factor_description\": null, \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": null, \"bar_sort_order\": 10, \"record_number\": 0}, {\"column_name\": \"Prior\", \"label_for_charts\": \"Starting match weight (prior)\", \"sql_condition\": null, \"log2_bayes_factor\": -8.386106589561935, \"bayes_factor\": 0.002989030659078392, \"comparison_vector_value\": null, \"m_probability\": null, \"u_probability\": null, \"bayes_factor_description\": null, \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": null, \"bar_sort_order\": 0, \"record_number\": 1}, {\"sql_condition\": \"\\\"first_name_l\\\" IS NULL OR \\\"first_name_r\\\" IS NULL\", \"label_for_charts\": \"first_name is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `first_name is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"first_name\", \"value_l\": \"Gabriel\", \"value_r\": \"None\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 1, \"record_number\": 1}, {\"sql_condition\": \"\\\"first_name_l\\\" IS NULL OR \\\"first_name_r\\\" IS NULL\", \"label_for_charts\": \"first_name is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `first_name is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"tf_first_name\", \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 2, \"record_number\": 1}, {\"sql_condition\": \"\\\"surname_l\\\" = \\\"surname_r\\\"\", \"label_for_charts\": \"Exact match on surname\", \"m_probability\": 0.43457460622893745, \"u_probability\": 0.004889975550122249, \"bayes_factor\": 88.87050697381771, \"log2_bayes_factor\": 6.473632813130572, \"comparison_vector_value\": 4, \"bayes_factor_description\": \"If comparison level is `exact match on surname` then comparison is 88.87 times more likely to be a match\", \"column_name\": \"surname\", \"value_l\": \"Thomas\", \"value_r\": \"Thomas\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 3, \"record_number\": 1}, {\"sql_condition\": \"\\\"surname_l\\\" = \\\"surname_r\\\"\", \"label_for_charts\": \"Term freq adjustment on surname with weight {cl.tf_adjustment_weight}\", \"m_probability\": null, \"u_probability\": null, \"bayes_factor\": 1.0012224938875305, \"log2_bayes_factor\": 0.0017626086992596967, \"comparison_vector_value\": 4, \"bayes_factor_description\": \"Term frequency adjustment on surname makes comparison 1.00 times more likely to be a match\", \"column_name\": \"tf_surname\", \"value_l\": \"Thomas\", \"value_r\": \"Thomas\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 4, \"record_number\": 1}, {\"sql_condition\": \"ELSE\", \"label_for_charts\": \"All other comparisons\", \"m_probability\": 0.4592001552927498, \"u_probability\": 0.9966506506506506, \"bayes_factor\": 0.4607433457179473, \"log2_bayes_factor\": -1.1179647649923994, \"comparison_vector_value\": 0, \"bayes_factor_description\": \"If comparison level is `all other comparisons` then comparison is  2.17 times less likely to be a match\", \"column_name\": \"dob\", \"value_l\": \"1977-09-13\", \"value_r\": \"1977-10-17\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 5, \"record_number\": 1}, {\"sql_condition\": \"\\\"city_l\\\" = \\\"city_r\\\"\", \"label_for_charts\": \"Exact match on city\", \"m_probability\": 0.5625747223574914, \"u_probability\": 0.0551475711801453, \"bayes_factor\": 10.201260188228096, \"log2_bayes_factor\": 3.350675477967206, \"comparison_vector_value\": 1, \"bayes_factor_description\": \"If comparison level is `exact match on city` then comparison is 10.20 times more likely to be a match\", \"column_name\": \"city\", \"value_l\": \"London\", \"value_r\": \"London\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 6, \"record_number\": 1}, {\"sql_condition\": \"\\\"city_l\\\" = \\\"city_r\\\"\", \"label_for_charts\": \"Term freq adjustment on city with weight {cl.tf_adjustment_weight}\", \"m_probability\": null, \"u_probability\": null, \"bayes_factor\": 0.2591617073379083, \"log2_bayes_factor\": -1.948075527570922, \"comparison_vector_value\": 1, \"bayes_factor_description\": \"Term frequency adjustment on city makes comparison  3.86 times less likely to be a match\", \"column_name\": \"tf_city\", \"value_l\": \"London\", \"value_r\": \"London\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 7, \"record_number\": 1}, {\"sql_condition\": \"\\\"email_l\\\" IS NULL OR \\\"email_r\\\" IS NULL\", \"label_for_charts\": \"email is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `email is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"email\", \"value_l\": \"gabriel.t54@nichols.info\", \"value_r\": \"None\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 8, \"record_number\": 1}, {\"sql_condition\": \"\\\"email_l\\\" IS NULL OR \\\"email_r\\\" IS NULL\", \"label_for_charts\": \"email is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `email is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"tf_email\", \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 9, \"record_number\": 1}, {\"column_name\": \"Final score\", \"label_for_charts\": \"Final score\", \"sql_condition\": null, \"log2_bayes_factor\": -1.6260759823282191, \"bayes_factor\": 0.323968178497503, \"comparison_vector_value\": null, \"m_probability\": null, \"u_probability\": null, \"bayes_factor_description\": null, \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": null, \"bar_sort_order\": 10, \"record_number\": 1}, {\"column_name\": \"Prior\", \"label_for_charts\": \"Starting match weight (prior)\", \"sql_condition\": null, \"log2_bayes_factor\": -8.386106589561935, \"bayes_factor\": 0.002989030659078392, \"comparison_vector_value\": null, \"m_probability\": null, \"u_probability\": null, \"bayes_factor_description\": null, \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": null, \"bar_sort_order\": 0, \"record_number\": 2}, {\"sql_condition\": \"jaro_winkler_similarity(\\\"first_name_l\\\", \\\"first_name_r\\\") >= 0.7\", \"label_for_charts\": \"Jaro-Winkler distance of first_name >= 0.7\", \"m_probability\": 0.07908610771504865, \"u_probability\": 0.018934945558406913, \"bayes_factor\": 4.176727494203714, \"log2_bayes_factor\": 2.06237301958744, \"comparison_vector_value\": 1, \"bayes_factor_description\": \"If comparison level is `jaro-winkler distance of first_name >= 0.7` then comparison is 4.18 times more likely to be a match\", \"column_name\": \"first_name\", \"value_l\": \"geeorGe\", \"value_r\": \"George\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 1, \"record_number\": 2}, {\"sql_condition\": \"jaro_winkler_similarity(\\\"first_name_l\\\", \\\"first_name_r\\\") >= 0.7\", \"label_for_charts\": \"Jaro-Winkler distance of first_name >= 0.7\", \"m_probability\": 0.07908610771504865, \"u_probability\": 0.018934945558406913, \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": 1, \"bayes_factor_description\": \"If comparison level is `jaro-winkler distance of first_name >= 0.7` then comparison is 4.18 times more likely to be a match\", \"column_name\": \"tf_first_name\", \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 2, \"record_number\": 2}, {\"sql_condition\": \"\\\"surname_l\\\" = \\\"surname_r\\\"\", \"label_for_charts\": \"Exact match on surname\", \"m_probability\": 0.43457460622893745, \"u_probability\": 0.004889975550122249, \"bayes_factor\": 88.87050697381771, \"log2_bayes_factor\": 6.473632813130572, \"comparison_vector_value\": 4, \"bayes_factor_description\": \"If comparison level is `exact match on surname` then comparison is 88.87 times more likely to be a match\", \"column_name\": \"surname\", \"value_l\": \"Davidson\", \"value_r\": \"Davidson\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 3, \"record_number\": 2}, {\"sql_condition\": \"\\\"surname_l\\\" = \\\"surname_r\\\"\", \"label_for_charts\": \"Term freq adjustment on surname with weight {cl.tf_adjustment_weight}\", \"m_probability\": null, \"u_probability\": null, \"bayes_factor\": 0.6674816625916871, \"log2_bayes_factor\": -0.5831998920218964, \"comparison_vector_value\": 4, \"bayes_factor_description\": \"Term frequency adjustment on surname makes comparison  1.50 times less likely to be a match\", \"column_name\": \"tf_surname\", \"value_l\": \"Davidson\", \"value_r\": \"Davidson\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 4, \"record_number\": 2}, {\"sql_condition\": \"ELSE\", \"label_for_charts\": \"All other comparisons\", \"m_probability\": 0.4592001552927498, \"u_probability\": 0.9966506506506506, \"bayes_factor\": 0.4607433457179473, \"log2_bayes_factor\": -1.1179647649923994, \"comparison_vector_value\": 0, \"bayes_factor_description\": \"If comparison level is `all other comparisons` then comparison is  2.17 times less likely to be a match\", \"column_name\": \"dob\", \"value_l\": \"1999-05-07\", \"value_r\": \"2000-05-06\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 5, \"record_number\": 2}, {\"sql_condition\": \"\\\"city_l\\\" IS NULL OR \\\"city_r\\\" IS NULL\", \"label_for_charts\": \"city is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `city is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"city\", \"value_l\": \"Southamptn\", \"value_r\": \"None\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 6, \"record_number\": 2}, {\"sql_condition\": \"\\\"city_l\\\" IS NULL OR \\\"city_r\\\" IS NULL\", \"label_for_charts\": \"city is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `city is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"tf_city\", \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 7, \"record_number\": 2}, {\"sql_condition\": \"\\\"email_l\\\" IS NULL OR \\\"email_r\\\" IS NULL\", \"label_for_charts\": \"email is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `email is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"email\", \"value_l\": \"None\", \"value_r\": \"gdavidson@johnson-brown.com\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 8, \"record_number\": 2}, {\"sql_condition\": \"\\\"email_l\\\" IS NULL OR \\\"email_r\\\" IS NULL\", \"label_for_charts\": \"email is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `email is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"tf_email\", \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 9, \"record_number\": 2}, {\"column_name\": \"Final score\", \"label_for_charts\": \"Final score\", \"sql_condition\": null, \"log2_bayes_factor\": -1.551265413858219, \"bayes_factor\": 0.3412106508773083, \"comparison_vector_value\": null, \"m_probability\": null, \"u_probability\": null, \"bayes_factor_description\": null, \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": null, \"bar_sort_order\": 10, \"record_number\": 2}, {\"column_name\": \"Prior\", \"label_for_charts\": \"Starting match weight (prior)\", \"sql_condition\": null, \"log2_bayes_factor\": -8.386106589561935, \"bayes_factor\": 0.002989030659078392, \"comparison_vector_value\": null, \"m_probability\": null, \"u_probability\": null, \"bayes_factor_description\": null, \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": null, \"bar_sort_order\": 0, \"record_number\": 3}, {\"sql_condition\": \"\\\"first_name_l\\\" = \\\"first_name_r\\\"\", \"label_for_charts\": \"Exact match on first_name\", \"m_probability\": 0.49142094931763786, \"u_probability\": 0.0057935713975033705, \"bayes_factor\": 84.82176460782142, \"log2_bayes_factor\": 6.406362591550453, \"comparison_vector_value\": 4, \"bayes_factor_description\": \"If comparison level is `exact match on first_name` then comparison is 84.82 times more likely to be a match\", \"column_name\": \"first_name\", \"value_l\": \"Toby\", \"value_r\": \"Toby\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 1, \"record_number\": 3}, {\"sql_condition\": \"\\\"first_name_l\\\" = \\\"first_name_r\\\"\", \"label_for_charts\": \"Term freq adjustment on first_name with weight {cl.tf_adjustment_weight}\", \"m_probability\": null, \"u_probability\": null, \"bayes_factor\": 1.2036144578313253, \"log2_bayes_factor\": 0.2673733415581312, \"comparison_vector_value\": 4, \"bayes_factor_description\": \"Term frequency adjustment on first_name makes comparison 1.20 times more likely to be a match\", \"column_name\": \"tf_first_name\", \"value_l\": \"Toby\", \"value_r\": \"Toby\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 2, \"record_number\": 3}, {\"sql_condition\": \"\\\"surname_l\\\" IS NULL OR \\\"surname_r\\\" IS NULL\", \"label_for_charts\": \"surname is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `surname is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"surname\", \"value_l\": \"None\", \"value_r\": \"None\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 3, \"record_number\": 3}, {\"sql_condition\": \"\\\"surname_l\\\" IS NULL OR \\\"surname_r\\\" IS NULL\", \"label_for_charts\": \"surname is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `surname is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"tf_surname\", \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 4, \"record_number\": 3}, {\"sql_condition\": \"ELSE\", \"label_for_charts\": \"All other comparisons\", \"m_probability\": 0.4592001552927498, \"u_probability\": 0.9966506506506506, \"bayes_factor\": 0.4607433457179473, \"log2_bayes_factor\": -1.1179647649923994, \"comparison_vector_value\": 0, \"bayes_factor_description\": \"If comparison level is `all other comparisons` then comparison is  2.17 times less likely to be a match\", \"column_name\": \"dob\", \"value_l\": \"2003-04-23\", \"value_r\": \"2013-03-21\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 5, \"record_number\": 3}, {\"sql_condition\": \"\\\"city_l\\\" = \\\"city_r\\\"\", \"label_for_charts\": \"Exact match on city\", \"m_probability\": 0.5625747223574914, \"u_probability\": 0.0551475711801453, \"bayes_factor\": 10.201260188228096, \"log2_bayes_factor\": 3.350675477967206, \"comparison_vector_value\": 1, \"bayes_factor_description\": \"If comparison level is `exact match on city` then comparison is 10.20 times more likely to be a match\", \"column_name\": \"city\", \"value_l\": \"London\", \"value_r\": \"London\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 6, \"record_number\": 3}, {\"sql_condition\": \"\\\"city_l\\\" = \\\"city_r\\\"\", \"label_for_charts\": \"Term freq adjustment on city with weight {cl.tf_adjustment_weight}\", \"m_probability\": null, \"u_probability\": null, \"bayes_factor\": 0.2591617073379083, \"log2_bayes_factor\": -1.948075527570922, \"comparison_vector_value\": 1, \"bayes_factor_description\": \"Term frequency adjustment on city makes comparison  3.86 times less likely to be a match\", \"column_name\": \"tf_city\", \"value_l\": \"London\", \"value_r\": \"London\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 7, \"record_number\": 3}, {\"sql_condition\": \"\\\"email_l\\\" IS NULL OR \\\"email_r\\\" IS NULL\", \"label_for_charts\": \"email is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `email is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"email\", \"value_l\": \"toby.d@menhez.com\", \"value_r\": \"None\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 8, \"record_number\": 3}, {\"sql_condition\": \"\\\"email_l\\\" IS NULL OR \\\"email_r\\\" IS NULL\", \"label_for_charts\": \"email is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `email is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"tf_email\", \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 9, \"record_number\": 3}, {\"column_name\": \"Final score\", \"label_for_charts\": \"Final score\", \"sql_condition\": null, \"log2_bayes_factor\": -1.4277354710494674, \"bayes_factor\": 0.37171389638898916, \"comparison_vector_value\": null, \"m_probability\": null, \"u_probability\": null, \"bayes_factor_description\": null, \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": null, \"bar_sort_order\": 10, \"record_number\": 3}, {\"column_name\": \"Prior\", \"label_for_charts\": \"Starting match weight (prior)\", \"sql_condition\": null, \"log2_bayes_factor\": -8.386106589561935, \"bayes_factor\": 0.002989030659078392, \"comparison_vector_value\": null, \"m_probability\": null, \"u_probability\": null, \"bayes_factor_description\": null, \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": null, \"bar_sort_order\": 0, \"record_number\": 4}, {\"sql_condition\": \"\\\"first_name_l\\\" = \\\"first_name_r\\\"\", \"label_for_charts\": \"Exact match on first_name\", \"m_probability\": 0.49142094931763786, \"u_probability\": 0.0057935713975033705, \"bayes_factor\": 84.82176460782142, \"log2_bayes_factor\": 6.406362591550453, \"comparison_vector_value\": 4, \"bayes_factor_description\": \"If comparison level is `exact match on first_name` then comparison is 84.82 times more likely to be a match\", \"column_name\": \"first_name\", \"value_l\": \"Toby\", \"value_r\": \"Toby\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 1, \"record_number\": 4}, {\"sql_condition\": \"\\\"first_name_l\\\" = \\\"first_name_r\\\"\", \"label_for_charts\": \"Term freq adjustment on first_name with weight {cl.tf_adjustment_weight}\", \"m_probability\": null, \"u_probability\": null, \"bayes_factor\": 1.2036144578313253, \"log2_bayes_factor\": 0.2673733415581312, \"comparison_vector_value\": 4, \"bayes_factor_description\": \"Term frequency adjustment on first_name makes comparison 1.20 times more likely to be a match\", \"column_name\": \"tf_first_name\", \"value_l\": \"Toby\", \"value_r\": \"Toby\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 2, \"record_number\": 4}, {\"sql_condition\": \"\\\"surname_l\\\" IS NULL OR \\\"surname_r\\\" IS NULL\", \"label_for_charts\": \"surname is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `surname is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"surname\", \"value_l\": \"Haall\", \"value_r\": \"None\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 3, \"record_number\": 4}, {\"sql_condition\": \"\\\"surname_l\\\" IS NULL OR \\\"surname_r\\\" IS NULL\", \"label_for_charts\": \"surname is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `surname is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"tf_surname\", \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 4, \"record_number\": 4}, {\"sql_condition\": \"ELSE\", \"label_for_charts\": \"All other comparisons\", \"m_probability\": 0.4592001552927498, \"u_probability\": 0.9966506506506506, \"bayes_factor\": 0.4607433457179473, \"log2_bayes_factor\": -1.1179647649923994, \"comparison_vector_value\": 0, \"bayes_factor_description\": \"If comparison level is `all other comparisons` then comparison is  2.17 times less likely to be a match\", \"column_name\": \"dob\", \"value_l\": \"2003-04-23\", \"value_r\": \"2013-03-21\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 5, \"record_number\": 4}, {\"sql_condition\": \"\\\"city_l\\\" = \\\"city_r\\\"\", \"label_for_charts\": \"Exact match on city\", \"m_probability\": 0.5625747223574914, \"u_probability\": 0.0551475711801453, \"bayes_factor\": 10.201260188228096, \"log2_bayes_factor\": 3.350675477967206, \"comparison_vector_value\": 1, \"bayes_factor_description\": \"If comparison level is `exact match on city` then comparison is 10.20 times more likely to be a match\", \"column_name\": \"city\", \"value_l\": \"London\", \"value_r\": \"London\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 6, \"record_number\": 4}, {\"sql_condition\": \"\\\"city_l\\\" = \\\"city_r\\\"\", \"label_for_charts\": \"Term freq adjustment on city with weight {cl.tf_adjustment_weight}\", \"m_probability\": null, \"u_probability\": null, \"bayes_factor\": 0.2591617073379083, \"log2_bayes_factor\": -1.948075527570922, \"comparison_vector_value\": 1, \"bayes_factor_description\": \"Term frequency adjustment on city makes comparison  3.86 times less likely to be a match\", \"column_name\": \"tf_city\", \"value_l\": \"London\", \"value_r\": \"London\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 7, \"record_number\": 4}, {\"sql_condition\": \"\\\"email_l\\\" IS NULL OR \\\"email_r\\\" IS NULL\", \"label_for_charts\": \"email is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `email is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"email\", \"value_l\": \"None\", \"value_r\": \"None\", \"term_frequency_adjustment\": false, \"bar_sort_order\": 8, \"record_number\": 4}, {\"sql_condition\": \"\\\"email_l\\\" IS NULL OR \\\"email_r\\\" IS NULL\", \"label_for_charts\": \"email is NULL\", \"bayes_factor\": 1.0, \"log2_bayes_factor\": 0.0, \"comparison_vector_value\": -1, \"bayes_factor_description\": \"If comparison level is `email is null` then comparison is 1.00 times more likely to be a match\", \"column_name\": \"tf_email\", \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": true, \"bar_sort_order\": 9, \"record_number\": 4}, {\"column_name\": \"Final score\", \"label_for_charts\": \"Final score\", \"sql_condition\": null, \"log2_bayes_factor\": -1.4277354710494674, \"bayes_factor\": 0.37171389638898916, \"comparison_vector_value\": null, \"m_probability\": null, \"u_probability\": null, \"bayes_factor_description\": null, \"value_l\": \"\", \"value_r\": \"\", \"term_frequency_adjustment\": null, \"bar_sort_order\": 10, \"record_number\": 4}]}}, {\"mode\": \"vega-lite\"});\n",
              "</script>"
            ],
            "text/plain": [
              "alt.LayerChart(...)"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "records_to_view = df_predictions.as_record_dict(limit=5)\n",
        "linker.visualisations.waterfall_chart(records_to_view, filter_nulls=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "48b76176",
      "metadata": {},
      "source": [
        "## Comparison viewer dashboard\n",
        "\n",
        "The [comparison viewer dashboard](../../api_docs/visualisations.md#splink.internals.linker_components.visualisations.LinkerVisualisations.comparison_viewer_dashboard) takes this one step further by producing an interactive dashboard that contains example predictions from across the spectrum of match scores.\n",
        "\n",
        "An in-depth video describing how to interpret the dashboard can be found [here](https://www.youtube.com/watch?v=DNvCMqjipis).\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "da85169c",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2024-06-22T08:35:38.618191Z",
          "iopub.status.busy": "2024-06-22T08:35:38.617967Z",
          "iopub.status.idle": "2024-06-22T08:35:38.717561Z",
          "shell.execute_reply": "2024-06-22T08:35:38.716858Z"
        },
        "tags": []
      },
      "outputs": [
        {
          "data": {
            "text/html": [
              "\n",
              "        <iframe\n",
              "            width=\"100%\"\n",
              "            height=\"1200\"\n",
              "            src=\"./scv.html\"\n",
              "            frameborder=\"0\"\n",
              "            allowfullscreen\n",
              "            \n",
              "        ></iframe>\n",
              "        "
            ],
            "text/plain": [
              "<IPython.lib.display.IFrame at 0x12d6db2e0>"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "linker.visualisations.comparison_viewer_dashboard(df_predictions, \"scv.html\", overwrite=True)\n",
        "\n",
        "# You can view the scv.html file in your browser, or inline in a notbook as follows\n",
        "from IPython.display import IFrame\n",
        "\n",
        "IFrame(src=\"./scv.html\", width=\"100%\", height=1200)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d34df82c",
      "metadata": {},
      "source": [
        "## Cluster studio dashboard\n",
        "\n",
        "Cluster studio is an interactive dashboards that visualises the results of clustering your predictions.\n",
        "\n",
        "It provides examples of clusters of different sizes. The shape and size of clusters can be indicative of problems with record linkage, so it provides a tool to help you find potential false positive and negative links.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "e2153d91",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2024-06-22T08:35:38.721856Z",
          "iopub.status.busy": "2024-06-22T08:35:38.721546Z",
          "iopub.status.idle": "2024-06-22T08:35:38.845614Z",
          "shell.execute_reply": "2024-06-22T08:35:38.844884Z"
        },
        "tags": []
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Completed iteration 1, root rows count 2\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Completed iteration 2, root rows count 0\n"
          ]
        },
        {
          "data": {
            "text/html": [
              "\n",
              "        <iframe\n",
              "            width=\"100%\"\n",
              "            height=\"1000\"\n",
              "            src=\"./cluster_studio.html\"\n",
              "            frameborder=\"0\"\n",
              "            allowfullscreen\n",
              "            \n",
              "        ></iframe>\n",
              "        "
            ],
            "text/plain": [
              "<IPython.lib.display.IFrame at 0x12d80bfa0>"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "df_clusters = linker.clustering.cluster_pairwise_predictions_at_threshold(\n",
        "    df_predictions, threshold_match_probability=0.5\n",
        ")\n",
        "\n",
        "linker.visualisations.cluster_studio_dashboard(\n",
        "    df_predictions,\n",
        "    df_clusters,\n",
        "    \"cluster_studio.html\",\n",
        "    sampling_method=\"by_cluster_size\",\n",
        "    overwrite=True,\n",
        ")\n",
        "\n",
        "# You can view the scv.html file in your browser, or inline in a notbook as follows\n",
        "from IPython.display import IFrame\n",
        "\n",
        "IFrame(src=\"./cluster_studio.html\", width=\"100%\", height=1000)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "20ede1e9",
      "metadata": {},
      "source": [
        "!!! note \"Further Reading\"\n",
        "\n",
        "    :material-tools: For more on the visualisation tools in Splink, please refer to the [Visualisation API documentation](../../api_docs/visualisations.md).\n",
        "\n",
        "    :bar_chart: For more on the charts used in this tutorial, please refer to the [Charts Gallery](../../charts/index.md#model-evaluation).\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7cc780cb",
      "metadata": {},
      "source": [
        "## Next steps\n",
        "\n",
        "Now we have visualised the results of a model, we can move on to some more formal Quality Assurance procedures using labelled data.\n"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3 (ipykernel)",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.10.8"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
